package com.vrp3d.common.response;

import com.vrp3d.common.enums.CommonExceptionEnum;
import com.vrp3d.common.exceptions.BusinessException;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.authz.UnauthenticatedException;
import org.apache.shiro.authz.UnauthorizedException;
import org.springframework.http.HttpStatus;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.validation.BindException;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.MissingServletRequestParameterException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.multipart.MaxUploadSizeExceededException;

import javax.validation.ConstraintViolationException;
import java.util.Objects;

/**
 * 全局异常处理
 *
 * @author vrp3d
 */
@Slf4j
@ControllerAdvice
public class GlobalHandler {

    /**
     * 权限异常统一处理
     *
     * @return
     */
    @ExceptionHandler({UnauthorizedException.class})
    @ResponseStatus(HttpStatus.UNAUTHORIZED)
    @ResponseBody
    public RestResponse processUnAuthenticatedException() {
        log.error("权限不足");
        return new RestResponse(RestResponse.RestResult.DENIED);
    }

    /**
     * 捕获注解校验,未登录异常
     *
     * @return
     */
    @ExceptionHandler({UnauthenticatedException.class})
    @ResponseStatus(HttpStatus.UNAUTHORIZED)
    @ResponseBody
    public RestResponse processUnauthenticatedException(UnauthenticatedException e) {
        log.error("shiro注解校验,用户未登录," + e);
        return new RestResponse(RestResponse.RestResult.DENIED);
    }

    /**
     * 请求方式错误
     *
     * @return
     */
    @ExceptionHandler({HttpRequestMethodNotSupportedException.class})
    @ResponseStatus(HttpStatus.METHOD_NOT_ALLOWED)
    @ResponseBody
    public RestResponse httpRequestMethodNotSupportedException(HttpRequestMethodNotSupportedException e) {
        log.error("请求方式错误," + e.getMessage());
        return new RestResponse(RestResponse.RestResult.METHOD_NOT_ALLOWED);
    }

    /**
     * 所有业务异常统一处理
     *
     * @param ex
     * @return
     */
    @ExceptionHandler({BusinessException.class})
    @ResponseStatus(HttpStatus.OK)
    @ResponseBody
    public RestResponse resolveException(BusinessException ex) {
        log.error(ex.toString());
        return new RestResponse(ex.getCode(), ex.getMessage());
    }

    /**
     * 所有非业务异常统一处理
     *
     * @param ex
     * @return
     */
    @ExceptionHandler({HttpMessageNotReadableException.class})
    @ResponseStatus(HttpStatus.OK)
    @ResponseBody
    public RestResponse resolveParamException(HttpMessageNotReadableException ex) {
        log.error("请求JSON格式错误，" + ex.getMessage());
        return new RestResponse(RestResponse.RestResult.WRONG);
    }

    /**
     * 所有非业务异常统一处理
     *
     * @param ex
     * @return
     */
    @ExceptionHandler({RuntimeException.class})
    @ResponseStatus(HttpStatus.OK)
    @ResponseBody
    public RestResponse resolveException1(RuntimeException ex) {
        log.error(ex.toString());
        return new RestResponse(RestResponse.RestResult.ERROR);
    }

    /**
     * 请求参数名错误
     *
     * @param ex
     * @return
     */
    @ExceptionHandler({MissingServletRequestParameterException.class})
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    @ResponseBody
    public RestResponse parameterException(MissingServletRequestParameterException ex) {
        log.error("请求参数名错误," + ex.toString());
        return new RestResponse(RestResponse.RestResult.BAD_REQUEST);
    }

    /**
     * 请求参数名错误(使用group验证时)
     *
     * @param ex
     * @return
     */
    @ExceptionHandler({MethodArgumentNotValidException.class})
    @ResponseStatus(HttpStatus.OK)
    @ResponseBody
    public RestResponse methodArgumentNotValidException(MethodArgumentNotValidException ex) {
        log.error("请求参数错误," + ex.toString());
        return new RestResponse(CommonExceptionEnum.REQUEST_PARAMETER_FORMAT_ERROR.getCode(), Objects.requireNonNull(ex.getBindingResult().getFieldError()).getDefaultMessage());
    }

    /**
     * 参数异常
     *
     * @param ex
     * @return
     */
    @ExceptionHandler({BindException.class})
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    @ResponseBody
    public RestResponse bindException(BindException ex) {
        log.error("参数异常(注解验证)," + ex.toString());
        return new RestResponse(RestResponse.RestResult.BAD_REQUEST);
    }

    /**
     * get方式参数校验异常
     *
     * @param ex
     * @return
     */
    @ExceptionHandler({ConstraintViolationException.class})
    @ResponseStatus(HttpStatus.OK)
    @ResponseBody
    public RestResponse processConstraintViolationException(ConstraintViolationException ex) {
        log.error("get方式参数校验异常," + ex.toString());
        return new RestResponse(CommonExceptionEnum.REQUEST_PARAMETER_FORMAT_ERROR.getCode(), ex.getMessage().substring(ex.getMessage().lastIndexOf(":") + 2));
    }

    /**
     * 上传文件大小超限
     *
     * @param ex
     * @return
     */
    @ExceptionHandler({MaxUploadSizeExceededException.class})
    @ResponseStatus(HttpStatus.OK)
    @ResponseBody
    public RestResponse maxUploadSizeExceededException(MaxUploadSizeExceededException ex) {
        log.error("上传文件超出系统限定大小," + ex.toString());
        return new RestResponse(RestResponse.RestResult.ERROR);
    }
}
